﻿using MathNet.Numerics;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.Statistics;
using System;
using System.Collections.Generic;
using System.Linq;
using static System.Formats.Asn1.AsnWriter;

namespace DataAnalyticsTools.Core
{
    public static class MathHelper
    {
        /// <summary>
        /// 欧拉-马歇罗尼常数,Gamma
        /// </summary>
        public const double EULER_MASCHERONI = 0.5772156649015328606;

        /// <summary>
        /// 最小标准差常量，防止除零错误和数值不稳定
        /// 在计算标准差比率时作为分母的保护值
        /// </summary>
        public const float MIN_STD_DEV = 1e-10f;

        /// <summary>
        /// 标准化数据（Z-score标准化）
        /// </summary>
        public static float[][] Standardize(float[][] data)
        {
            if (data == null || data.Length == 0)
                return data;

            int featureCount = data[0].Length;
            var standardized = new float[data.Length][];

            for (int i = 0; i < data.Length; i++)
            {
                standardized[i] = new float[featureCount];
            }

            for (int j = 0; j < featureCount; j++)
            {
                var column = data.Select(row => (double)row[j]).ToArray();
                var mean = column.Mean();
                var std = column.StandardDeviation();

                for (int i = 0; i < data.Length; i++)
                {
                    standardized[i][j] = std != 0 ? (float)((data[i][j] - mean) / std) : 0f;
                }
            }

            return standardized;
        }

        /// <summary>
        /// 归一化数据（Min-Max归一化）
        /// </summary>
        public static float[][] Normalize(float[][] data)
        {
            if (data == null || data.Length == 0)
                return data;

            int featureCount = data[0].Length;
            var normalized = new float[data.Length][];

            for (int i = 0; i < data.Length; i++)
            {
                normalized[i] = new float[featureCount];
            }

            for (int j = 0; j < featureCount; j++)
            {
                var column = data.Select(row => row[j]).ToArray();
                var min = column.Min();
                var max = column.Max();
                var range = max - min;

                for (int i = 0; i < data.Length; i++)
                {
                    normalized[i][j] = range != 0 ? (data[i][j] - min) / range : 0.5f;
                }
            }

            return normalized;
        }

        /// <summary>
        /// 计算协方差矩阵
        /// </summary>
        public static float[,] CovarianceMatrix(float[][] data)
        {
            if (data == null || data.Length == 0)
                return new float[0, 0];

            int n = data.Length;
            int p = data[0].Length;
            var covMatrix = new float[p, p];

            for (int i = 0; i < p; i++)
            {
                for (int j = i; j < p; j++)
                {
                    var col1 = data.Select(row => (double)row[i]).ToArray();
                    var col2 = data.Select(row => (double)row[j]).ToArray();
                    var cov = CalculateCovariance(col1, col2);
                    covMatrix[i, j] = covMatrix[j, i] = (float)cov;
                }
            }

            return covMatrix;
        }

        /// <summary>
        /// 自行实现的协方差计算方法，MathNet.Numerics 中的 Correlation.Covariance比较麻烦。
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static double CalculateCovariance(double[] x, double[] y)
        {
            if (x.Length != y.Length || x.Length == 0)
                throw new ArgumentException("数组长度必须相同且不为空");

            if (x.Length == 1)
                return 0.0;  // 单个样本协方差为0

            double meanX = x.Average();
            double meanY = y.Average();
            double sum = 0;

            for (int i = 0; i < x.Length; i++)
            {
                sum += (x[i] - meanX) * (y[i] - meanY);
            }

            return sum / (x.Length - 1);  // 样本协方差
        }


        public static float EuclideanDistance(float[] a, float[] b)
        {
            float sum = 0;
            for (int i = 0; i < a.Length; i++)
            {
                sum += (a[i] - b[i]) * (a[i] - b[i]);
            }
            return (float)Math.Sqrt(sum);
        }

        /// <summary>
        /// 对特征矩阵按列做 Min-Max 缩放到 [0,1]。
        /// 如果某列的 max==min，则该列全部赋值为 0（避免 NaN）。
        /// 返回新的矩阵（深拷贝）。
        /// </summary>
        public static float[][] MinMaxScale(float[][] features)
        {
            if (features == null || features.Length == 0) return features;

            int n = features.Length;
            int m = features[0].Length;
            var scaled = new float[n][];
            for (int i = 0; i < n; i++) scaled[i] = new float[m];

            for (int j = 0; j < m; j++)
            {
                float min = float.PositiveInfinity;
                float max = float.NegativeInfinity;
                for (int i = 0; i < n; i++)
                {
                    float v = features[i][j];
                    if (v < min) min = v;
                    if (v > max) max = v;
                }

                float denom = max - min;
                if (!float.IsFinite(min) || !float.IsFinite(max) || Math.Abs(denom) < 1e-9f)
                {
                    // 常数列或异常值：全部置为 0
                    for (int i = 0; i < n; i++) scaled[i][j] = 0f;
                }
                else
                {
                    for (int i = 0; i < n; i++)
                        scaled[i][j] = (features[i][j] - min) / denom;
                }
            }

            return scaled;
        }

        /// <summary>
        /// 对特征矩阵按列做 Z-score 标准化（均值0，方差1）。
        /// 若标准差接近0，则该列全部减去均值（等于0）。
        /// 返回新的矩阵（深拷贝）。
        /// </summary>
        public static float[][] ZScoreScale(float[][] features)
        {
            if (features == null || features.Length == 0) return features;

            int n = features.Length;
            int m = features[0].Length;
            var scaled = new float[n][];
            for (int i = 0; i < n; i++) scaled[i] = new float[m];

            for (int j = 0; j < m; j++)
            {
                double sum = 0;
                for (int i = 0; i < n; i++) sum += features[i][j];
                double mean = sum / n;

                double var = 0;
                for (int i = 0; i < n; i++)
                {
                    var diff = features[i][j] - mean;
                    var += diff * diff;
                }
                double std = Math.Sqrt(var / n); // population std

                if (std < 1e-9)
                {
                    // 常数列：全部置为 0（均值处理后为0）
                    for (int i = 0; i < n; i++) scaled[i][j] = 0f;
                }
                else
                {
                    for (int i = 0; i < n; i++)
                        scaled[i][j] = (float)((features[i][j] - mean) / std);
                }
            }

            return scaled;
        }

        /// <summary>
        /// 对一维数组做 Min-Max 归一化到 [clipLow, clipHigh]（默认 [0,1]）。
        /// 若 max==min，返回全部 0 数组。
        /// </summary>
        public static float[] MinMaxNormalize(float[] values, float clipLow = 0f, float clipHigh = 1f)
        {
            if (values == null || values.Length == 0) return values;

            float min = values.Min();
            float max = values.Max();
            if (Math.Abs(max - min) < 1e-9f)
                return Enumerable.Repeat(0f, values.Length).ToArray();

            float scale = (clipHigh - clipLow) / (max - min);
            return values.Select(v => (v - min) * scale + clipLow).ToArray();
        }

        public static float[] MaxNormalize(float[] scores)
        {
            if (scores == null || scores.Length == 0)
                return scores;

            var max = scores.Max();
            if (max == 0) return scores;

            return scores.Select(s => s / max).ToArray();
        }


        /// <summary>
        /// 计算标准差
        /// </summary>
        public static float CalculateStdDev(float[] data)
        {
            if (data.Length < 2)
                return 0f;

            float mean = data.Average();
            float sumSquaredDiff = data.Sum(x => (x - mean) * (x - mean));
            return (float)Math.Sqrt(sumSquaredDiff / data.Length);
        }

        /// <summary>
        /// 计算中位数
        /// </summary>
        /// <param name="data">原始数据</param>
        /// <returns></returns>
        public static float CalculateMedian(float[] data)
        {
            var sorted = data.OrderBy(x => x).ToArray();
            int n = sorted.Length;

            if (n % 2 == 0)
            {
                return (sorted[n / 2 - 1] + sorted[n / 2]) / 2f;
            }
            else
            {
                return sorted[n / 2];
            }
        }
    }
}
